El objetivo general de la evaluación es aprender a implementar los modelos de Data Science explicados en el módulo 5. Para este fin hemos escogido una base de datos del año 2017 para predecir el total del precio de casas en el mercado de Pekín (totalPrice) a través de diferentes métodos y algoritmos con el objetivo de seleccionar aquel o aquellos métodos que sean más óptimos.

Variables de la base de datos

  • Lng : coordenada de longitud utilizando el protocolo BD09

  • Lat: coordenada de latitud utilizando el protocolo BD09

  • DOM: días activos en el mercado. Más información en https://en.wikipedia.org/wiki/Days_on_market

  • followers: el número de personas que siguen la transacción.

  • square: número total de metros.

  • livingRoom: número de habitaciones.

  • drawingRoom: número de salones.

  • kitchen: número de cocinas.

  • bathroom: número de baños.

  • floor: el número total de pisos en el edificio.

  • buildingType: (tower) torre (1), bungalow (2), (combination of plate and tower), combinación de lámina y torre (3), (plate) lámina (4)

  • renovationCondition: Otros (1), ásperas (2), sencillez (3), duras (4)

  • buildingStructure: desconocida (1), mixta (2), ladrillo y madera (3), ladrillo y cemento (4), acero (5) acero y hormigón (6).

  • ladderRatio: Describe cuántas escaleras tiene un residente en promedio.

  • elevator: tiene ascensor (1) no tiene ascensor (0)

  • fiveYearsProperty: si el dueño tiene la propiedad por menos de 5 años (1) en caso contrario (0)

  • subway: si está cerca el metro (1) en caso contario (0)

  • price: precio por metro cuadrado en yuanes.

  • totalPrice: precio total en millones de yuanes.

Tareas encomendadas

  • Preprocesado de la información:

    Dada la transcendencia de esta primera fase del análisis y de la cantidad de tiempo y recursos que conlleva (entre el 70 y el 80 por ciento del trabajo real) se considera muy importante realizar a fondo esta tarea antes de aplicar los modelos.

  • Resúmenes de la información a través de tablas y análisis gráficos.

  • Análisis de correlación.

  • Estudio de valores faltantes y valores extremos.

  • Selección de variables.

Otros tratamientos que se consideren oportunos.

  • Aplicación de Modelos:

Especifique y justifique cómo utiliza la muestra para la estimación de los modelos.

Métodos básicos para la REGRESIÓN:

  • Árboles de decisión. (CART y Random Forest)

  • Métodos de vecindad (K-vecinos)

  • Redes Neuronales. (Perceptron Multicapa)

  • Máquinas de vectores soporte.

  • Bagging y Boosting.

  • Gradient Boosting.

  • Explicabilidad del modelo elegido como óptimo.

Se valorará que se incluyan otros modelos y algoritmos que se consideren oportunos. Por ejemplo: Regresión Lineal, Regresión Lasso, y/o Redes neuronales de Base Radial, etcétera.

1. Carga de Librerías

En esta primera fase preparamos el entorno de trabajo cargando las librerías necesarias. Para ello, comprobamos previamente si están instaladas en el sistema. A continuación, cargamos los datos del mercado inmobiliario de Pekín del año 2017, que utilizaremos para desarrollar y evaluar distintos modelos de predicción.

# Instalación de paquetes solo si es necesario
if (!require("tidyverse")) install.packages("tidyverse")
if (!require("readr")) install.packages("readr")
if (!require("janitor")) install.packages("janitor")
if (!require("skimr")) install.packages("skimr")
if (!require("caret")) install.packages("caret")
if (!require("GGally")) install.packages("GGally")
if (!require("corrplot")) install.packages("corrplot")
if (!require("rpart")) install.packages("rpart")
if (!require("randomForest")) install.packages("randomForest")
if (!require("class")) install.packages("class")
if (!require("nnet")) install.packages("nnet")
if (!require("e1071")) install.packages("e1071")
if (!require("gbm")) install.packages("gbm")
if (!require("xgboost")) install.packages("xgboost")
if (!require("DALEX")) install.packages("DALEX")
if (!require("DALEXtra")) install.packages("DALEXtra")
if (!require("forcats")) install.packages("forcats")
if (!require("recipes")) install.packages("recipes")
if (!require("tidymodels")) install.packages("tidymodels")
if (!require("data.table")) install.packages("data.table")
if (!require("kableExtra")) install.packages("kableExtra")
if (!require("magrittr")) install.packages("magrittr")
if (!require("inspectdf")) install.packages("inspectdf")
if (!require("reactable")) install.packages("reactable")
if (!require("ggmap")) install.packages("ggmap")
if (!require("ggdensity")) install.packages("ggdensity")
if (!require("geomtextpath")) install.packages("geomtextpath")

# Carga de librerías
library(tidyverse)
library(readr)
library(janitor)
library(skimr)
library(caret)
library(GGally)
library(corrplot)
library(rpart)
library(randomForest)
library(class)
library(nnet)
library(e1071)
library(gbm)
library(xgboost)
library(DALEX)
library(DALEXtra)
library(forcats)
library(recipes)
library(tidymodels)
library(data.table)
library(kableExtra)
library(magrittr)   # Para usar %<>%
library(inspectdf)
library(reactable)
library(ggmap)
library(ggdensity)
library(geomtextpath)

2. Etapa EDA (Exploratory Data Analysis)

Leemos el fichero original con los datos del mercado inmobiliario de Pekín del año 2017. A continuación, realizamos una limpieza básica: eliminamos posibles filas duplicadas y transformamos algunas variables numéricas en variables categóricas, ya que representan información cualitativa. Posteriormente, mostramos las primeras observaciones.

# Leer el conjunto de datos original
datOri <- fread('/Users/oscar/Desktop/BIG DATA/2o TRIMESTRE/MODULO 5_Mineria de datos 1/3_Autoevaluacion/M05_AutoEv_Oscar Porta/mercado_beijing_2017.csv') %>% 
  as.data.table()

# Eliminar filas duplicadas
datOri %<>% 
  distinct() %>%
  as.data.table()

# Conversión de variables numéricas a factores
datOri %<>%
  mutate( buildingType        = as.factor(buildingType)) %>%
  mutate( renovationCondition = as.factor(renovationCondition)) %>%
  mutate( buildingStructure   = as.factor(buildingStructure)) %>%
  mutate( fiveYearsProperty   = as.factor(fiveYearsProperty)) %>%
  mutate( subway              = as.factor(subway)) %>%
  mutate( elevator            = as.factor(elevator)) %>%
  as.data.table()

# Visualización interactiva de las primeras observaciones con estilo reactable
reactable(head(datOri, 10),
          bordered = TRUE,
          highlight = TRUE,
          striped = TRUE,
          pagination = FALSE,
          class = "reactable-table")


Realizamos un análisis automático del conjunto de datos utilizando funciones de la librería inspectdf. Esto nos permitirá entender mejor la estructura, distribución y calidad de los datos antes de realizar cualquier modelado. Representamos las correlaciones más fuertes, los desequilibrios de categorías, el uso de memoria, la presencia de valores ausentes y las distribuciones de variables numéricas.

# EDA automático de variables categóricas
x <- inspect_cat(datOri)
show_plot(x)

# Correlación entre columnas numéricas (solo las mayores o iguales a 0.5 en valor absoluto)
x <- inspect_cor(datOri)
x <- x %>% dplyr::filter(abs(corr) >= 0.5 | corr <= -0.5) %>% as_tibble()
show_plot(x)

# Categoría más frecuente por cada variable categórica
x <- inspect_imb(datOri)
show_plot(x)

# Uso de memoria por columna
x <- inspect_mem(datOri)
show_plot(x)

# Porcentaje de valores NA por columna
x <- inspect_na(datOri)
show_plot(x)

# Histogramas de variables numéricas
x <- inspect_num(datOri)
show_plot(x)

# Tipo de cada variable
x <- inspect_types(datOri)
show_plot(x)


De esta primera iteración en el EDA, obtenemos las siguientes conclusiones:

Variables categóricas:

La mayoría de variables presentan la cardinalidad esperada según la descripción original del dataset.

Frecuencia mayoritaria en variables categóricas:

  • buildingStructure: 6 (71%)

  • elevator: 1 (70%)

  • subway: 1 (60%)

  • fiveYearsProperty: 1 (56%)

  • renovationCondition: 1 (46%)

  • buildingType: 4 (38%)

Datos faltantes (porcentaje):

  • buildingType: 4.2%

Correlación de variables (top 5):

  • livingRoom - square: 0.743

  • bathRoom - square: 0.716

  • square - totalPrice: 0.644

  • drawingRoom - square: 0.580

Variables numéricas destacadas:

  • DOM presenta valores atípicos por encima de 1000, cuando el 75% está por debajo de 200.

  • followers tiene valores extremos por encima de 600, con una mediana de 3.

  • ladderRatio tiene una mediana de 0.33 pero llega hasta valores de 10.

  • price y square presentan distribuciones asimétricas, concentradas en valores bajos y colas largas a la derecha.

A partir de este análisis, tomamos las siguientes decisiones:

  • Imputaremos buildingType, que presenta un porcentaje reducido de valores perdidos.

  • Aunque algunas variables numéricas presentan outliers, por ahora solo tomamos nota para decidir más adelante posibles transformaciones.

  • Recodificamos los niveles de las variables categóricas para facilitar su interpretación en gráficos y modelos.

# Recodificar buildingType
datOri$buildingType <- factor(datOri$buildingType,
                              labels = c("torre", "bungalow", "combinacion", "lamina"))

# Recodificar renovationCondition
datOri$renovationCondition <- factor(datOri$renovationCondition,
                                     labels = c("otros", "asperas", "sencillez", "duras"))

# Recodificar buildingStructure
datOri$buildingStructure <- factor(datOri$buildingStructure,
                                   labels = c("desconocida", "mixta", "ladrillo y madera",
                                              "ladrillo y cemento", "acero", "acero y hormigon"))

# Recodificar elevator
datOri$elevator <- factor(datOri$elevator,
                          labels = c("No", "Si"))

# Recodificar fiveYearsProperty
datOri$fiveYearsProperty <- factor(datOri$fiveYearsProperty,
                                   labels = c("No", "Si"))

# Recodificar subway
datOri$subway <- factor(datOri$subway,
                        labels = c("No", "Si"))

# Volver a graficar composición de variables categóricas
x <- inspect_cat(datOri)
show_plot(x)

3. Visualización de Datos Espaciales

Antes de proceder a la modelización, realizamos una visualización espacial básica para observar la distribución geográfica de diferentes variables del dataset. En concreto, representamos la localización de los inmuebles según varias variables categóricas y el precio. Esto nos permite detectar si existe una posible concentración geográfica asociada a ciertas categorías, lo cual puede ser relevante en el análisis predictivo posterior.

# Visualización geográfica sin mapa base (pero manteniendo lat/lon)

# Función general para graficar distribución geográfica por variable
mapa_simple_por_variable <- function(var) {
  ggplot(datOri, aes(x = Lng, y = Lat, color = .data[[var]])) +
    geom_point(alpha = 0.6, size = 1.3) +
    facet_wrap(as.formula(paste("~", var))) +
    ggtitle(paste("Distribución espacial según:", var)) +
    theme_minimal() +
    theme(axis.title = element_blank())
}

# Mapas categóricos
mapa_simple_por_variable("buildingType")

mapa_simple_por_variable("subway")

mapa_simple_por_variable("elevator")

mapa_simple_por_variable("buildingStructure")

mapa_simple_por_variable("renovationCondition")

# Mapa continuo de price
ggplot(datOri, aes(x = Lng, y = Lat, color = price)) +
  geom_point(size = 1.3, alpha = 0.9) +
  ggtitle("Distribución espacial de Price") +
  theme_minimal() +
  theme(axis.title = element_blank())

Del análisis espacial realizado a partir de las coordenadas de longitud y latitud, podemos extraer las siguientes observaciones clave para cada una de las variables representadas:

  • buildingType:

Observamos que los edificios del tipo “torre” se concentran principalmente en el centro de la ciudad, mientras que en las zonas periféricas predomina el tipo “lámina”. Además, detectamos un pequeño núcleo urbano con presencia destacada de edificios tipo “bungalow”, lo que podría corresponder a un casco antiguo o una zona residencial tradicional.

  • subway:

Las viviendas cercanas a estaciones de metro se concentran en el centro de Pekín. En la periferia, la proporción de propiedades cerca del metro disminuye notablemente, lo que puede estar reflejando una menor densidad de infraestructuras de transporte público en esas zonas.

  • elevator:

Las propiedades con ascensor se encuentran principalmente en el área central de la ciudad. En cambio, en los barrios periféricos predominan las propiedades sin ascensor, lo cual podría relacionarse con la antigüedad de las construcciones o con edificios de menor altura.

  • buildingStructure:

En el centro de la ciudad se concentran las estructuras más modernas, construidas en acero y hormigón. En cambio, hacia la periferia predominan las construcciones mixtas o de ladrillo y cemento. También se identifica un punto donde se concentran edificaciones de ladrillo y madera, lo que podría indicar una zona de valor histórico o residencial tradicional.

  • renovationCondition:

No se detecta un patrón espacial claro en cuanto al estado de renovación de las propiedades. Los distintos niveles de esta variable se encuentran distribuidos de forma bastante homogénea a lo largo del mapa.

  • price:

Los precios por metro cuadrado tienden a ser más elevados en el centro urbano, donde además la densidad de viviendas es mayor. A medida que nos alejamos del centro hacia las zonas periféricas, los precios disminuyen, lo que refleja una clara correlación espacial entre localización y valor del inmueble.

4. Modelo Inicial H2O

Antes de construir modelos con transformaciones más cuidadas, decidimos ejecutar un primer modelo baseline usando la función h2o.automl(), que nos permite probar múltiples algoritmos automáticamente y obtener información valiosa como:

  • El tipo de modelo con mejor ajuste.

  • Un valor de referencia del error del modelo (baseline).

  • La importancia relativa de las variables.

En primer lugar, inicializamos el entorno de H2O para poder lanzar modelos de machine learning sobre nuestra base de datos. Esta operación se realiza solo una vez por sesión y debe ejecutarse de forma interactiva, no al generar el documento HTML.

# Inicializar H2O
library(h2o)
h2o.init()
h2o.no_progress()

Este bloque debe ejecutarse manualmente cada vez que se abra RStudio, pero no se ejecuta al knitear para evitar errores de conexión con H2O.


A continuación, ejecutamos el primer modelo baseline con H2O AutoML. Este proceso entrena múltiples modelos automáticamente durante 5 minutos, usando validación cruzada y dejando fuera GLM y StackedEnsemble para centrarnos en métodos más complejos. Este bloque se ejecuta exclusivamente en RStudio y se desactiva al generar el HTML (eval=FALSE) para evitar errores o entrenamientos innecesarios.

# Convertir a formato H2O
data <- as.h2o(datOri)

# Dividir el dataset (train, valid, test)
splits <- h2o.splitFrame(
  data = data, 
  ratios = c(0.7, 0.15),
  destination_frames = c("train", "valid", "test"),
  seed = 1
)
train <- splits[[1]]
valid <- splits[[2]]
test  <- splits[[3]]

# Definir variables
y <- "totalPrice"
x <- setdiff(names(data), y)

# Ejecutar H2O AutoML (5 minutos, sin GLM ni StackedEnsemble)
aml <- h2o.automl(
  x                  = x,
  y                  = y,
  training_frame     = train,
  validation_frame   = valid,
  nfold              = 3,
  max_runtime_secs   = 300,
  stopping_metric    = "RMSE",
  exclude_algos      = c("GLM", "StackedEnsemble"),
  stopping_tolerance = 0.1,
  stopping_rounds    = 5,
  seed               = 12345,
  sort_metric        = "RMSE"
)

Una vez finaliza la ejecución del AutoML, guardamos los resultados más relevantes: el modelo líder, su tabla de rendimiento, el gráfico de importancia de variables y el error RMSE. Esto nos permite volver a usarlos más adelante sin reentrenar.

# Guardar leaderboard, modelo, RMSE y variable importancia
best_mod     <- aml@leader
lb_df        <- as.data.frame(aml@leaderboard)
var_import   <- h2o.varimp(best_mod)
aml_perf     <- h2o.performance(model = best_mod, newdata = test)
err_val_pre  <- h2o.rmse(aml_perf)

# Crear carpeta si no existe
if (!dir.exists("resultados")) dir.create("resultados")

# Guardar todo
h2o.saveModel(best_mod, path = "resultados", force = TRUE)
saveRDS(lb_df, file = "resultados/lb_df.rds")
saveRDS(var_import, file = "resultados/var_import.rds")
saveRDS(err_val_pre, file = "resultados/err_val_pre.rds")
saveRDS(best_mod, file = "resultados/best_mod.rds")

Para mostrar los resultados en el informe sin volver a ejecutar el modelo, cargamos los objetos guardados en el paso anterior. Este bloque sí se ejecuta al knit.

# Cargar leaderboard, RMSE y variable importance guardados
lb_df        <- readRDS("resultados/lb_df.rds")
var_import   <- readRDS("resultados/var_import.rds")
err_val_pre  <- readRDS("resultados/err_val_pre.rds")
best_mod     <- readRDS("resultados/best_mod.rds") 

Mostramos a continuación los resultados más relevantes del AutoML: los 10 mejores y 10 peores modelos, el gráfico de importancia de variables y el RMSE obtenido en test. Este bloque sí se ejecuta al knit.

# Top-10 mejores modelos
lb_df %>% head(10) %>%
  kbl(caption = "Top-10 Mejores Modelos Ejecutados - Ordenados por RMSE") %>%
  kable_minimal()
Top-10 Mejores Modelos Ejecutados - Ordenados por RMSE
model_id rmse mse mae rmsle mean_residual_deviance
GBM_grid_1_AutoML_1_20250603_84523_model_112 40.63040 1650.830 8.095330 0.1039192 1650.830
GBM_grid_1_AutoML_1_20250603_84523_model_165 41.26995 1703.208 7.626729 NA 1703.208
GBM_grid_1_AutoML_1_20250603_84523_model_9 41.79594 1746.900 11.603605 NA 1746.900
DeepLearning_grid_1_AutoML_1_20250603_84523_model_1 42.06689 1769.623 17.125697 NA 1769.623
DeepLearning_grid_1_AutoML_1_20250603_84523_model_2 43.17752 1864.298 17.165955 NA 1864.298
GBM_grid_1_AutoML_1_20250603_84523_model_252 43.70957 1910.526 11.025980 NA 1910.526
GBM_grid_1_AutoML_1_20250603_84523_model_150 44.15492 1949.657 19.201593 NA 1949.657
GBM_grid_1_AutoML_1_20250603_84523_model_170 44.31392 1963.723 9.774251 NA 1963.723
GBM_grid_1_AutoML_1_20250603_84523_model_52 44.66802 1995.232 9.240851 0.1066327 1995.232
GBM_grid_1_AutoML_1_20250603_84523_model_68 45.24717 2047.306 15.756929 NA 2047.306
# Top-10 peores modelos
lb_df %>% tail(10) %>%
  kbl(caption = "Top-10 Peores Modelos Ejecutados - Ordenados por RMSE") %>%
  kable_minimal()
Top-10 Peores Modelos Ejecutados - Ordenados por RMSE
model_id rmse mse mae rmsle mean_residual_deviance
275 GBM_grid_1_AutoML_1_20250603_84523_model_136 108.7975 11836.89 42.69203 0.2523016 11836.89
276 GBM_grid_1_AutoML_1_20250603_84523_model_11 108.8203 11841.86 43.50324 0.2504584 11841.86
277 GBM_grid_1_AutoML_1_20250603_84523_model_89 109.7195 12038.36 40.84170 NA 12038.36
278 GBM_grid_1_AutoML_1_20250603_84523_model_100 110.7469 12264.88 47.28652 0.2563844 12264.88
279 GBM_grid_1_AutoML_1_20250603_84523_model_233 111.1368 12351.38 42.45046 0.2553346 12351.38
280 GBM_grid_1_AutoML_1_20250603_84523_model_39 112.5641 12670.68 60.59995 NA 12670.68
281 DeepLearning_grid_1_AutoML_1_20250603_84523_model_4 113.5529 12894.26 41.24660 NA 12894.26
282 GBM_grid_1_AutoML_1_20250603_84523_model_234 115.9740 13449.97 51.25668 0.2734822 13449.97
283 GBM_grid_1_AutoML_1_20250603_84523_model_172 125.0143 15628.59 56.31988 0.2874309 15628.59
284 GBM_grid_1_AutoML_1_20250603_84523_model_94 127.2491 16192.34 58.92600 0.2941695 16192.34
# Gráfico de variables importantes
ggplot(var_import[1:10, ], aes(x = fct_reorder(variable, scaled_importance), y = scaled_importance)) +
  geom_col(fill = 'darkgreen') +
  coord_flip() +
  labs(
    title    = "VARIABLES IMPORTANTES",
    subtitle = "Top-10",
    y        = 'Importancia Escalada',
    x        = "Variable"
  ) +
  theme_bw() +
  theme(
    plot.title   = element_text(size = 14, face = "bold", colour = "black"),
    axis.title.x = element_text(size = 14, face = "bold", colour = "black"),
    axis.title.y = element_text(size = 14, face = "bold", colour = "black"),
    axis.text.x  = element_text(size = 12, face = "bold", colour = "black"),
    axis.text.y  = element_text(size = 12, face = "bold", colour = "black")
  )

# Mostrar RMSE final
err_val_pre
## [1] 74.94872
# Mostrar modelo ganador
best_mod
## Model Details:
## ==============
## 
## H2ORegressionModel: gbm
## Model ID:  GBM_grid_1_AutoML_1_20250603_84523_model_112 
## Model Summary: 
##   number_of_trees number_of_internal_trees model_size_in_bytes min_depth
## 1              71                       71             1253678        13
##   max_depth mean_depth min_leaves max_leaves mean_leaves
## 1        13   13.00000        180       2264  1402.70420
## 
## 
## H2ORegressionMetrics: gbm
## ** Reported on training data. **
## 
## MSE:  0.5027646
## RMSE:  0.7090589
## MAE:  0.2773273
## RMSLE:  0.008203069
## Mean Residual Deviance :  0.5027646
## 
## 
## H2ORegressionMetrics: gbm
## ** Reported on validation data. **
## ** Validation metrics **
## 
## MSE:  2253.33
## RMSE:  47.46925
## MAE:  7.501601
## RMSLE:  0.1254609
## Mean Residual Deviance :  2253.33
## 
## 
## H2ORegressionMetrics: gbm
## ** Reported on cross-validation data. **
## ** 3-fold cross-validation on training data (Metrics computed for combined holdout predictions) **
## 
## MSE:  1650.83
## RMSE:  40.6304
## MAE:  8.09533
## RMSLE:  0.1039192
## Mean Residual Deviance :  1650.83
## 
## 
## Cross-Validation Metrics Summary: 
##                               mean         sd  cv_1_valid cv_2_valid
## mae                       8.095536   1.005594    7.020234   8.253695
## mean_residual_deviance 1650.873700 842.582300 1420.309400 947.574650
## mse                    1650.873700 842.582300 1420.309400 947.574650
## r2                        0.977121   0.011315    0.979123   0.987301
## residual_deviance      1650.873700 842.582300 1420.309400 947.574650
## rmse                     39.770000  10.189754   37.686993  30.782701
## rmsle                     0.096042   0.048629    0.062442   0.073878
##                         cv_3_valid
## mae                       9.012679
## mean_residual_deviance 2584.736800
## mse                    2584.736800
## r2                        0.964938
## residual_deviance      2584.736800
## rmse                     50.840310
## rmsle                     0.151804

Conclusiones del modelo baseline AutoML

Tras ejecutar el primer modelo base con H2O AutoML durante 5 minutos, se han entrenado un total de 284 modelos, siendo el mejor de ellos un modelo de tipo Gradient Boosting Machine (GBM). Este modelo alcanza un RMSE de 40.63 en validación cruzada y de 74.95 en la muestra de test, lo que constituye nuestro error base o baseline para comparaciones futuras.

El análisis de importancia de variables nos muestra una concentración muy clara en solo dos variables: square (superficie en metros cuadrados del inmueble) y price (precio por metro cuadrado). Ambas dominan la predicción con muchísima diferencia respecto al resto de variables.

Este resultado confirma que estas dos variables actúan como predictoras excesivas (hiperpredictoras), especialmente price, que está directamente relacionada con la variable objetivo totalPrice, lo que puede generar sobreajuste y resta valor interpretativo al modelo desde una perspectiva empresarial.

El resto de variables (como bathRoom, buildingType, fiveYearsProperty o floor) tienen un peso mínimo, lo cual puede estar condicionado por la fuerte influencia de square y price. En próximos pasos, eliminaremos estas variables y construiremos nuevas transformaciones (feature engineering) con el objetivo de mejorar la interpretabilidad y robustez del modelo.

5. Feature Enginering

Con el conocimiento adquirido tras la ejecución de nuestro primer modelo AutoML, en el que observamos una fuerte dependencia de las variables square y price, decidimos realizar una fase de ingeniería de variables para mejorar la explicabilidad y robustez del modelo.

En primer lugar, decidimos eliminar las variables price, square y DOM por su posible papel como variables hiperpredictoras o de escasa aportación predictiva independiente.

A continuación, construimos nuevas variables con el objetivo de capturar relaciones relevantes en el contexto de la predicción del precio total:

  • fe_dist: calculamos la distancia euclídea entre la localización de la vivienda (Lng, Lat) y un punto de referencia. Esta variable nos permite incorporar una medida de ubicación más refinada.

  • fe_tothabi: agregamos el número total de habitaciones (livingRoom, drawingRoom, kitchen, bathRoom) como un único indicador de tamaño funcional del piso.

  • fe_factors: unificamos todas las variables categóricas en un único string que resume la composición del piso. Esta transformación puede capturar interacciones complejas entre factores.

*Imputamos la variable buildingType en aquellos registros con valores NA, utilizando el resto de variables como referencia.

Con estas transformaciones, preparamos un nuevo dataset y volvemos a ejecutar un modelo de AutoML con H2O para evaluar el impacto de estos cambios.